package com.yichi.manager;

import android.util.Log;

import com.licheedev.modbus4android.ModbusCallback;
import com.licheedev.modbus4android.ModbusParam;
import com.licheedev.modbus4android.ModbusRespException;
import com.licheedev.modbus4android.ModbusWorker;
import com.licheedev.modbus4android.param.SerialParam;
import com.licheedev.modbus4android.param.TcpParam;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.serotonin.modbus4j.msg.ReadHoldingRegistersResponse;
import com.serotonin.modbus4j.msg.WriteRegisterResponse;
import com.serotonin.modbus4j.msg.WriteRegistersResponse;
import com.yichi.global.AppConfig;
import com.yichi.util.ByteUtil;
import com.yichi.util.ToastUtil;
import com.yichi.util.Utils;

import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * modbus rtu管理
 */
public class ModbusRtuManager extends ModbusWorker {

    private static final String TAG = "ModbusRtuManager";

    public ModbusRtuManager() {
    }

    /**
     * 初始化modbus tcp
     */
    public void initPlcTCP() {
        if (isModbusOpened()) {
            return;
        }

        // TCP
        ModbusParam tcpParam = TcpParam.create(AppConfig.PLC_MODBUS_HOST, AppConfig.PLC_MODBUS_PORT)
                .setEncapsulated(false)
                .setKeepAlive(true)
                .setTimeout(AppConfig.PLC_MODBUS_REQUEST_TIMEOUT)
                .setRetries(0);

        // 先把原来的关掉
        closeModbusMaster();
        init(tcpParam, new ModbusCallback<ModbusMaster>() {
            @Override
            public void onSuccess(ModbusMaster modbusMaster) {
                Log.i(TAG, "modbus网口打开成功");
            }

            @Override
            public void onFailure(Throwable tr) {
                Log.e(TAG, "modbus网口打开失败", tr);
            }

            @Override
            public void onFinally() {
            }
        });
    }

    /**
     * 初始化modbus rtu pcb
     */
    public void initPcbRTU() {

        if (isModbusOpened()) {
            return;
        }

        // 串口
        ModbusParam serialParam = SerialParam.create(AppConfig.PCB_MODBUS_PORTNAME, AppConfig.PCB_MODBUS_BAUDRATE)
                .setDataBits(AppConfig.PCB_MODBUS_DATA_BITS)
                .setStopBits(AppConfig.PCB_MODBUS_STOP_BITS)
                .setParity(AppConfig.PCB_MODBUS_PARITY)
                .setTimeout(AppConfig.PCB_MODBUS_REQUEST_TIMEOUT)
                .setRetries(0); // 不重试

        // 先把原来的关掉
        closeModbusMaster();
        init(serialParam, new ModbusCallback<ModbusMaster>() {
            @Override
            public void onSuccess(ModbusMaster modbusMaster) {
                Log.i(TAG, "modbus串口打开成功");
            }

            @Override
            public void onFailure(Throwable tr) {
                Log.e(TAG, "modbus串口打开失败", tr);
            }

            @Override
            public void onFinally() {
            }
        });
    }

    /**
     * 初始化modbus rtu iccard
     */
    public void initIccardRTU() {

        if (isModbusOpened()) {
            return;
        }

        // 串口
        ModbusParam serialParam = SerialParam.create(AppConfig.ICCARD_PORTNAME, Integer.parseInt(AppConfig.ICCARD_BAUDRATE))
                .setDataBits(AppConfig.ICCARD_DATA_BITS)
                .setStopBits(AppConfig.ICCARD_STOP_BITS)
                .setParity(AppConfig.ICCARD_PARITY)
                .setTimeout(AppConfig.ICCARD_REQUEST_TIMEOUT)
                .setRetries(0); // 不重试

        // 先把原来的关掉
        closeModbusMaster();
        init(serialParam, new ModbusCallback<ModbusMaster>() {
            @Override
            public void onSuccess(ModbusMaster modbusMaster) {
                Log.i(TAG, "modbus串口打开成功，iccard");
            }

            @Override
            public void onFailure(Throwable tr) {
                System.out.println("串口打开失败");
//                Log.e(TAG, "modbus串口打开失败，iccard", tr);
            }

            @Override
            public void onFinally() {
            }
        });
    }

    /**
     * 释放整个ModbusManager，单例会被置null
     */
    public synchronized void release() {
        super.release();
    }

    /**
     * 03 批量读取，WORD，一个寄存器2个字节
     *
     * @param slaveId
     * @param startOffset
     * @param count
     * @return
     */
    public ArrayList<Integer> readMultipleRegisters(int slaveId, int startOffset, int count) {
        final ArrayList<Integer>[] result = new ArrayList[1];
        final CountDownLatch latch = new CountDownLatch(1); // Used to block the thread until the response is received

        readHoldingRegisters(slaveId, startOffset, count, new ModbusCallback<ReadHoldingRegistersResponse>() {
            @Override
            public void onSuccess(ReadHoldingRegistersResponse readHoldingRegistersResponse) {
                byte[] data = readHoldingRegistersResponse.getData();
                Log.i(TAG, "串口03读取：" + ByteUtil.bytes2HexStr(data));

                result[0] = Utils.byteArray2IntegerList(data); // Store result in the array
                latch.countDown(); // Release the latch after receiving the response
            }

            @Override
            public void onFailure(Throwable tr) {
                // Handle failure, optionally set result to null or empty list
                result[0] = null;
                latch.countDown();
            }

            @Override
            public void onFinally() {
                // Optionally handle any cleanup
            }
        });

        try {
            boolean completed = latch.await(3, TimeUnit.SECONDS); // Wait with timeout
            if (!completed) {
                Log.e(TAG, "Timeout reached before response was received.");
                result[0] = null;
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            result[0] = null;
        }

        return result[0];
    }

    /**
     * 03 批量读取，WORD，一个寄存器2个字节
     *
     * @param slaveId
     * @param startOffset
     * @param count
     * @return
     */
    public byte[] readMultipleRegistersBytes(int slaveId, int startOffset, int count) {
        final byte[][] result = new byte[1][];
        final CountDownLatch latch = new CountDownLatch(1);

        // 在子线程执行读取任务，避免阻塞主线程
        new Thread(() -> {
            readHoldingRegisters(slaveId, startOffset, count, new ModbusCallback<ReadHoldingRegistersResponse>() {
                @Override
                public void onSuccess(ReadHoldingRegistersResponse response) {
                    byte[] data = response.getData();
                    Log.i(TAG, "串口03读取成功：" + ByteUtil.bytes2HexStr(data));
                    result[0] = data;
                    latch.countDown(); // 通知等待的线程
                }

                @Override
                public void onFailure(Throwable tr) {
                    Log.e(TAG, "串口03读取失败", tr);
                    result[0] = null;
                    latch.countDown();
                }

                @Override
                public void onFinally() {
                    // 可以加入一些日志或者清理操作
                    Log.i(TAG, "读取完成");
                }
            });
        }).start();

        try {
            boolean completed = latch.await(5000, TimeUnit.MILLISECONDS); // 5秒超时
            if (!completed) {
                Log.e(TAG, "读取超时！");
                result[0] = null;
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            Log.e(TAG, "线程被中断", e);
            result[0] = null;
        }

        return result[0];
    }

    /**
     * 调用库本身的同步方法
     *
     * @param slaveId
     * @param startOffset
     * @param count
     * @return
     * @throws ModbusInitException
     * @throws ModbusTransportException
     * @throws ModbusRespException
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public byte[] readMultipleRegistersBytesSync(int slaveId, int startOffset, int count) throws ModbusInitException, ModbusTransportException, ModbusRespException, ExecutionException, InterruptedException {
        ReadHoldingRegistersResponse readHoldingRegistersResponse = null;
        readHoldingRegistersResponse = syncReadHoldingRegisters(slaveId, startOffset, count);
        byte[] data = readHoldingRegistersResponse.getData();
        return data;
    }

    /**
     * 03 批量读取，WORD，一个寄存器2个字节
     *
     * @param slaveId
     * @param startOffset
     * @param count
     * @return
     */
    public void readMultipleRegistersCallback(int slaveId, int startOffset, int count, ModbusCallback<ReadHoldingRegistersResponse> callback) {
        readHoldingRegisters(slaveId, startOffset, count, callback);
    }

    /***
     *  保持寄存器写单个
     *  功能码为：06H，将数据写入至V存储器， 数据到真机，数据类型是Int,可以读写的数字类型(4x)
     * @param slaveId slaveId
     * @param writeOffset 开始位置
     * @param writeValue 写入的数据
     */
    public boolean writeRegister(int slaveId, int writeOffset, short writeValue) {
        final boolean[] result = new boolean[1]; // Store the result (true = success, false = failure)
        final CountDownLatch latch = new CountDownLatch(1); // Used to block the thread until the response is received

        writeSingleRegister(slaveId, writeOffset, writeValue, new ModbusCallback<WriteRegisterResponse>() {
            @Override
            public void onSuccess(WriteRegisterResponse writeRegisterResponse) {
                Log.i(TAG, "串口06写入成功");
                result[0] = true; // Set the result to true on success
                latch.countDown(); // Release the latch
            }

            @Override
            public void onFailure(Throwable tr) {
                Log.e(TAG, "串口06写入失败", tr);
                result[0] = false; // Set the result to false on failure
                latch.countDown(); // Release the latch
            }

            @Override
            public void onFinally() {
                // Optionally handle any cleanup
            }
        });

        try {
            boolean completed = latch.await(3, TimeUnit.SECONDS); // Block until latch is counted down or timeout
            if (!completed) {
                Log.e(TAG, "Timeout reached before response was received.");
                result[0] = false; // Timeout occurred, treat as failure
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            result[0] = false; // Handle interruption as failure
        }

        return result[0]; // Return the result (true for success, false for failure)
    }

    /**
     * 保持寄存器写入多个模拟量数据
     * 功能码为：10H,将数据写入至多个V存储器，写入数据到真机，数据类型是short[],可以读写的数字类型(4x)
     *
     * @param slaveId     modbus的slaveID
     * @param startOffset 起始位置偏移量值
     * @param sdata       写入的数据
     * @return 返回是否写入成功
     */
    public void writeRegistersCmd(int slaveId, int startOffset, short[] sdata) {
        writeRegisters(slaveId, startOffset, sdata, new ModbusCallback<WriteRegistersResponse>() {
            @Override
            public void onSuccess(WriteRegistersResponse writeRegistersResponse) {

            }

            @Override
            public void onFailure(Throwable tr) {

            }

            @Override
            public void onFinally() {

            }
        });
    }

    /**
     * 保持寄存器写入多个模拟量数据
     * 功能码为：10H,将数据写入至多个V存储器，写入数据到真机，数据类型是short[],可以读写的数字类型(4x)
     *
     * @param slaveId     modbus的slaveID
     * @param startOffset 起始位置偏移量值
     * @param sdata       写入的数据
     * @return 返回是否写入成功
     */
    public boolean writeRegistersEx(int slaveId, int startOffset, short[] sdata) {
        final boolean[] result = new boolean[1]; // Store the result (true = success, false = failure)
        final CountDownLatch latch = new CountDownLatch(1); // Used to block the thread until the response is received

        writeRegisters(slaveId, startOffset, sdata, new ModbusCallback<WriteRegistersResponse>() {
            @Override
            public void onSuccess(WriteRegistersResponse writeRegistersResponse) {
                Log.i(TAG, "串口10批量写入成功");
                result[0] = true; // Set the result to true on success
                latch.countDown(); // Release the latch
            }

            @Override
            public void onFailure(Throwable tr) {
                Log.e(TAG, "串口10批量写入失败", tr);
                result[0] = false; // Set the result to false on failure
                latch.countDown(); // Release the latch
            }

            @Override
            public void onFinally() {
                // Optionally handle any cleanup
            }
        });

        try {
            boolean completed = latch.await(3, TimeUnit.SECONDS); // Block until latch is counted down or timeout
            if (!completed) {
                Log.e(TAG, "Timeout reached before response was received.");
                result[0] = false; // Timeout occurred, treat as failure
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            result[0] = false; // Handle interruption as failure
        }

        return result[0]; // Return the result (true for success, false for failure)
    }
}